package com.huiyun.project.pay.biz.controller.pay.alipay;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.response.AlipayFundAuthOrderFreezeResponse;
import com.alipay.api.response.AlipayFundCouponOrderAgreementPayResponse;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.huiyun.project.common.core.domain.R;
import com.huiyun.project.common.core.util.fn.FunctionUtils;
import com.huiyun.project.common.security.annotation.Inner;
import com.huiyun.project.pay.biz.controller.BaseController;
import com.huiyun.project.pay.biz.dto.PayOrderDto;
import com.huiyun.project.pay.biz.entity.PayChannel;
import com.huiyun.project.pay.biz.handler.callback.impl.AliPayCallbackHandler;
import com.huiyun.project.pay.biz.handler.pay.AliPayHandler;
import com.huiyun.project.pay.biz.kit.PayConfigKit;
import com.huiyun.project.pay.biz.mq.NotifyProducer;
import com.huiyun.project.pay.biz.utils.StringUtils;
import com.huiyun.project.pay.client.consts.MchNotifyConst;
import com.huiyun.project.pay.client.consts.PayConst;
import com.huiyun.project.pay.client.vo.NotifyResp;
import com.huiyun.project.pay.client.vo.PayReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @author tiger
 */
@Controller
@RequestMapping("/aliPay")
@Api(tags = "支付宝支付")
@Slf4j
public class AliPayController extends BaseController {
    @Autowired
    private AliPayHandler aliPayHandler;

    @Autowired
    private NotifyProducer notifyProducer;

    @Autowired
    private AliPayCallbackHandler aliPayCallbackHandler;

    /**
     * 统一接口下单
     *
     * @param params
     * @return
     */
    @Inner(value = false)
    @PostMapping(value = "/payOrder/create")
    @ResponseBody
    @ApiOperation("阿里统一下单接口")
    public R payOrder(@RequestBody PayReq params) {
        return FunctionUtils.wrapper(() -> {
            PayConfigKit.init(params.getChannelAppId());
            log.info("-------------[商户统一下单]开始接收统一下单请求-------------");
            PayOrderDto payOrderDto = createPayOrder(params);
            String channelId = payOrderDto.getChannelId();
            if (PayConst.PAY_CHANNEL_ALIPAY_MOBILE.equals(channelId)) {
                return aliPayHandler.appPay(payOrderDto);
            } else if (PayConst.PAY_CHANNEL_ALIPAY_PC.equals(channelId)) {
                return aliPayHandler.pcPay(payOrderDto);
            } else if (PayConst.PAY_CHANNEL_ALIPAY_WAP.equals(channelId)) {
                return aliPayHandler.wapPay(payOrderDto);
            } else if (PayConst.PAY_CHANNEL_ALIPAY_QR.equals(channelId)) {
                return aliPayHandler.qrPay(payOrderDto);
            } else if (PayConst.PAY_CHANNEL_ALIPAY_BAR.equals(channelId)) {
                return aliPayHandler.barPay(payOrderDto);
            } else {
                return R.failed("不支持的阿里支付渠道类型[channelId=" + channelId + "]");
            }
        });
    }


    /**
     * 单笔转账到支付宝账户
     * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.54Ty29&
     * treeId=193&articleId=106236&docType=1
     */
    @RequestMapping(value = "/transfer")
    @ResponseBody
    public boolean transfer() {
        boolean isSuccess = false;
        String totalAmount = "66";
        AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
        model.setOutBizNo(StringUtils.getOutTradeNo());
        model.setPayeeType("ALIPAY_LOGONID");
        model.setPayeeAccount("abpkvd0206@sandbox.com");
        model.setAmount(totalAmount);
        model.setPayerShowName("测试退款");
        model.setPayerRealName("沙箱环境");
        model.setRemark("javen测试单笔转账到支付宝");

        try {
            isSuccess = AliPayApi.transfer(model);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isSuccess;
    }

    /**
     * 资金授权冻结接口
     */
    @RequestMapping(value = "/authOrderFreeze")
    @ResponseBody
    public AlipayFundAuthOrderFreezeResponse authOrderFreeze(@RequestParam("auth_code") String authCode) {
        try {
            AlipayFundAuthOrderFreezeModel model = new AlipayFundAuthOrderFreezeModel();
            model.setOutOrderNo(StringUtils.getOutTradeNo());
            model.setOutRequestNo(StringUtils.getOutTradeNo());
            model.setAuthCode(authCode);
            model.setAuthCodeType("bar_code");
            model.setOrderTitle("资金授权冻结-By IJPay");
            model.setAmount("36");
            model.setProductCode("PRE_AUTH");

            return AliPayApi.authOrderFreezeToResponse(model);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 红包协议支付接口
     * https://docs.open.alipay.com/301/106168/
     */
    @RequestMapping(value = "/agreementPay")
    @ResponseBody
    public AlipayFundCouponOrderAgreementPayResponse agreementPay() {
        try {
            AlipayFundCouponOrderAgreementPayModel model = new AlipayFundCouponOrderAgreementPayModel();
            model.setOutOrderNo(StringUtils.getOutTradeNo());
            model.setOutRequestNo(StringUtils.getOutTradeNo());
            model.setOrderTitle("红包协议支付接口-By IJPay");
            model.setAmount("36");
            model.setPayerUserId("2088102180432465");

            return AliPayApi.fundCouponOrderAgreementPayToResponse(model);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 下载对账单
     */
    @RequestMapping(value = "/dataDataserviceBill")
    @ResponseBody
    public String dataDataserviceBill(@RequestParam("billDate") String billDate) {
        try {
            AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
            model.setBillType("trade");
            model.setBillDate(billDate);
            return AliPayApi.billDownloadUrlQuery(model);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 交易查询
     */
    @RequestMapping(value = "/tradeQuery")
    @ResponseBody
    public boolean tradeQuery() {
        boolean isSuccess = false;
        try {
            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
            model.setOutTradeNo("081014283315023");
            model.setTradeNo("2017081021001004200200273870");

            isSuccess = AliPayApi.tradeQueryToResponse(model).isSuccess();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return isSuccess;
    }

    @RequestMapping(value = "/tradeQueryByStr")
    @ResponseBody
    public String tradeQueryByStr(@RequestParam("out_trade_no") String outTradeNo) {
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);

        try {
            return AliPayApi.tradeQueryToResponse(model).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 撤销订单
     */
    @RequestMapping(value = "/tradeCancel")
    @ResponseBody
    public boolean tradeCancel() {
        boolean isSuccess = false;
        try {
            AlipayTradeCancelModel model = new AlipayTradeCancelModel();
            model.setOutTradeNo("081014283315033");
            model.setTradeNo("2017081021001004200200274066");

            isSuccess = AliPayApi.tradeCancelToResponse(model).isSuccess();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return isSuccess;
    }

    /**
     * 关闭订单
     */
    @RequestMapping(value = "/tradeClose")
    @ResponseBody
    public String tradeClose(@RequestParam("out_trade_no") String outTradeNo, @RequestParam("trade_no") String tradeNo) {
        try {
            AlipayTradeCloseModel model = new AlipayTradeCloseModel();
            model.setOutTradeNo(outTradeNo);

            model.setTradeNo(tradeNo);

            return AliPayApi.tradeCloseToResponse(model).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 结算
     */
    @RequestMapping(value = "/tradeOrderSettle")
    @ResponseBody
    public String tradeOrderSettle(@RequestParam("trade_no") String tradeNo) {
        try {
            AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
            model.setOutRequestNo(StringUtils.getOutTradeNo());
            model.setTradeNo(tradeNo);

            return AliPayApi.tradeOrderSettleToResponse(model).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 退款通知
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/refundNotify/{channelAppId}")
    @ResponseBody
    @Inner(value = false)
    public String returnUrl(@PathVariable("channelAppId") String channelAppId, HttpServletRequest request) {
        try {
            PayConfigKit.init(channelAppId);
            // 获取支付宝GET过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            log.error("支付宝退款消息:" + JSON.toJSONString(params));
            //获取渠道配置信息
            AliPayApiConfig aliPayApiConfig = AliPayApiConfigKit.getApiConfig(channelAppId);
            boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAliPayPublicKey(), "UTF-8", "RSA2");
            PayChannel payChannel = payChannelService.getByChannelAppId(channelAppId);
            if (verifyResult) {
                log.info("支付退款消息验证成功");
                String mchOrderNo = params.get(PayConst.OUT_TRADE_NO);
                //发送支付事务MQ消息
                notifyProducer.sendMessage(new NotifyResp()
                        .setCode("SUCCESS")
                        .setMessage("成功")
                        .setDestination(PayConst.TOPIC_MALL_REFUND_NOTIFY)
                        .setMchId(payChannel.getMchId())
                        .setType(MchNotifyConst.TYPE.REFUND.getValue())
                        .setChannelId(payChannel.getChannelId())
                        .setMchOrderNo(mchOrderNo)
                        .setTradeNo(params.get("trade_no"))
                        .setTotalAmount(Convert.toLong(Convert.toDouble(params.get("total_amount")) * 100))
                        .setChannelAppId(channelAppId)
                        .setParams(params)
                );
                return "success";
            } else {
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }

    /**
     * 支付通知接口
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/payNotify/{channelAppId}")
    @ResponseBody
    @Inner(value = false)
    public String notifyUrl(@PathVariable("channelAppId") String channelAppId, HttpServletRequest request) {
        try {
            PayConfigKit.init(channelAppId);
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            log.info("接受到支付宝支付通知消息 channelAppId:{},data:{}", channelAppId, JSON.toJSONString(params));
            PayChannel payChannel = payChannelService.getByChannelAppId(channelAppId);
            //获取渠道配置信息
            AliPayApiConfig aliPayApiConfig = AliPayApiConfigKit.getApiConfig(channelAppId);
            //String aliPayPublicKey = JSON.parseObject(payChannel.getParam()).getString("aliPayPublicKey");
            //校验签名
            boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAliPayPublicKey(), "UTF-8", "RSA2");
            if (verifyResult) {
                log.info("支付宝支付通知消息验证成功");
                String mchOrderNo = params.get(PayConst.OUT_TRADE_NO);

                //发送支付事务MQ消息
                notifyProducer.sendMessage(new NotifyResp()
                        .setCode("SUCCESS")
                        .setMessage("成功")
                        .setDestination(PayConst.TOPIC_MALL_PAY_NOTIFY)
                        .setMchId(payChannel.getMchId())
                        .setType(MchNotifyConst.TYPE.PAY.getValue())
                        .setChannelId(payChannel.getChannelId())
                        .setMchOrderNo(mchOrderNo)
                        .setTradeNo(params.get("trade_no"))
                        //元转分
                        .setTotalAmount(Convert.toLong(Convert.toDouble(params.get("total_amount")) * 100))
                        .setChannelAppId(channelAppId)
                        .setParams(params)
                );
                return "success";
            } else {
                log.info("支付宝支付通知消息验证失败");
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }
}